package com.qf.votedemo.phone.service.impl;

import cn.hutool.jwt.JWT;
import com.qf.votedemo.phone.entity.Phone;
import com.qf.votedemo.phone.service.IPhoneService;
import com.qf.votedemo.phone.service.TokenServer;
import com.qf.votedemo.until.LocalCache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author 刘欣
 * @createTime 2023/2/27 19:08
 * @description
 */
@Service
public class TokenServerImpl implements TokenServer {

    @Autowired
    private IPhoneService phoneService;

    @Autowired
    private RedisTemplate redisTemplate;


    @Override
    public String crearToken(String num) throws Exception {
        //1、查看本地缓存是否存在phone对应的token
        Map<String, Object> jwtToken = LocalCache.jwtTokenCache.get(num);
        //2、用户电话第一次申请token
        if (jwtToken == null) {
            String newToken = createToken(num);
            Map<String, Object> cache = cacheToken(num, newToken);
            savePhone(num);
            LocalCache.jwtTokenCache.put(num, cache);
            return newToken;
        } else {
            //获得当前时间戳
            long currentTime = System.currentTimeMillis();
            //在本地缓存中获取创建token时间
            long time = (long) jwtToken.get("tiem");
            return getToken(num, jwtToken, currentTime, time);
        }
    }

    /**
     * 基于redis实现token颁发
     *
     * @param phoneNum
     * @return
     */
    @Override
    public String crearTokenRedis(String phoneNum) {
        //从redis缓存中获取token
        String jwtToken = (String) redisTemplate.opsForValue().get("token:" + phoneNum);
        if (jwtToken != null) {
            return jwtToken;
        } else {
            //获取token
            String newToken = createToken(phoneNum);
            //落库
            savePhone(phoneNum);
            //将生成的token存入redis缓存,设置生存时长60s
            redisTemplate.opsForValue().set("token:" + phoneNum, newToken, 60, TimeUnit.SECONDS);

            return newToken;
        }
    }

    /**
     * 判断token是否超时
     *
     * @param num
     * @param jwtToken
     * @param currentTime
     * @param time
     * @return
     */
    private String getToken(String num, Map<String, Object> jwtToken, long currentTime, long time) {
        //判断token是否超时
        if (currentTime - time <= 1000 * 60) {
            //token在60s内，从本地缓存中获取token返回
            String cacheToken = (String) jwtToken.get("token");
            return cacheToken;
        } else {
            //token超时重新颁发token
            String newToken = createToken(num);
            Map<String, Object> cache = cacheToken(num, newToken);
            LocalCache.jwtTokenCache.put(num, cache);
            return newToken;
        }
    }

    /**
     * 生成本地缓存token
     *
     * @param num
     * @param token
     * @return
     */
    private Map<String, Object> cacheToken(String num, String token) {
        Map<String, Object> cache = new HashMap<>();
        cache.put("time", System.currentTimeMillis());
        cache.put("token", token);
        return cache;
    }

    /**
     * 用户第一次获取token时保存电话号码
     *
     * @param num 电话号码
     */
    private void savePhone(String num) {
        Phone phone = phoneService.selectPhone(num);
        if (phone == null) {
            phoneService.savePhone(num);
        }
    }

    /**
     * 生成token,5分钟过期
     *
     * @param phoneNum
     * @return
     */
    private String createToken(String phoneNum) {
        String token = JWT.create().setPayload("phone", phoneNum).setExpiresAt(new Date(System.currentTimeMillis() + 1000 * 60 * 5))
                .setKey("qfjava2203".getBytes(StandardCharsets.UTF_8)).sign();
        return token;
    }
}
